package com.rocketmq.temp3.common.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.fasterxml.jackson.databind.node.JsonNodeType;
import com.fasterxml.jackson.databind.node.ObjectNode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.beans.BeanCopier;

import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

@Slf4j
public final class JsonUtils {

    private static ObjectMapper objectMapper;

    static {
        objectMapper = JacksonUtils.getDefaultMapper();
    }

    /**
     * Jackson解析Object对象，获取字段值
     */
    public static String readObject(Object object, String fieldName) {
        if (null == object) {
            return "";
        }
        JsonNode rootNode = objectMapper.valueToTree(object);
        if (null == rootNode) {
            return "";
        }
        JsonNode jsonNode = rootNode.get(fieldName);
        if (null == jsonNode) {
            return "";
        }
        return jsonNode.size() == 0 ? jsonNode.asText() : JacksonUtils.to(jsonNode);
    }

    /**
     * Jackson解析Json字符串，判断指定字段是否为数组类型，如果是则返回数组的长度
     */
    public static Integer validJsonArray(String jsonStr, String fieldKey) throws IOException {
        JsonNode rootNode = objectMapper.readTree(jsonStr);
        if (rootNode == null) {
            return 0;
        }
        JsonNode fieldNode = rootNode.get(fieldKey);
        if (fieldNode == null) {
            return 0;
        }
        if (JsonNodeType.ARRAY != fieldNode.getNodeType()) {
            return 0;
        }
        return fieldNode.size();
    }

    public static ObjectNode stringify(String jsonStr) {
        try {
            return (ObjectNode) objectMapper.readTree(jsonStr);
        } catch (JsonProcessingException e) {
            log.error(GenerateUtils.printException(e));
            return null;
        }
    }

    /**
     * 更新Json的值
     */
    public static String updateJson(String sourceJson, Map<String, Object> targetMap) throws IOException {
        ObjectNode rootObjectNode = (ObjectNode) objectMapper.readTree(sourceJson);
        targetMap.forEach((key, value) -> rootObjectNode.put(key, String.valueOf(value)));
        return objectMapper.writeValueAsString(rootObjectNode);
    }

    /**
     * 根据路径解析Json节点
     *
     * @param rootNode    JSON根节点
     * @param fullPathKey 节点路径
     * @return 返回最后的节点
     */
    public static JsonNode readPathNode(ObjectNode rootNode, String fullPathKey) {
        if (rootNode == null || rootNode.getNodeType() == JsonNodeType.ARRAY) {
            return null;
        }
        try {
            String[] pathKeyList = fullPathKey.split("\\.");
            JsonNode jsonNode = null;
            String pathKey;
            for (int i = 0; i < pathKeyList.length; i++) {
                pathKey = pathKeyList[i];
                if (jsonNode != null && jsonNode.getNodeType() == JsonNodeType.ARRAY) {
                    break;
                }
                jsonNode = i == 0
                        ? rootNode.get(pathKey)
                        : jsonNode != null
                        ? jsonNode.get(pathKey)
                        : null;
                if (i > 0 && jsonNode == null) {
                    break;
                }
            }
            return jsonNode;
        } catch (Exception ex) {
            log.error("readPathNode解析JSON异常：", ex);
            return null;
        }
    }

    /**
     * 读取文本节点的值
     */
    public static String readNode(JsonNode node, String key) {
        JsonNode keyNode = node.get(key);
        if (keyNode == null) {
            return "";
        }
        return Arrays.asList(JsonNodeType.STRING, JsonNodeType.NUMBER, JsonNodeType.BOOLEAN, JsonNodeType.NULL).contains(keyNode.getNodeType())
                ? keyNode.asText()
                : "";
    }

    /**
     * Java Bean 不同对象之间字段值的复制，所有的字段值都会被复制
     *
     * @param origin 从origin获取字段值
     * @param target 将所有从origin获取到的字段值复制到target对象
     * @return 返回赋值后的target对象
     */
    public static <T> T copyAllProperties(Object origin, T target) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            mapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

            ObjectReader objectReader = mapper.readerForUpdating(target);
            objectReader.readValue(mapper.writeValueAsString(origin));
            return target;
        } catch (IOException ex) {
            log.error(ex.getMessage(), ex);
            return null;
        }
    }

    /**
     * Java Bean 不同对象之间字段值的复制，非默认值的字段都会被复制
     *
     * @param origin 从origin获取字段值
     * @param target 将从origin获取到的字段值(非默认值)复制到target对象
     * @return 返回赋值后的target对象
     */
    public static <T> T copyNonNullProperties(Object origin, T target) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
            mapper.setSerializationInclusion(JsonInclude.Include.NON_DEFAULT);

            ObjectReader objectReader = mapper.readerForUpdating(target);
            objectReader.readValue(mapper.writeValueAsString(origin));
            return target;
        } catch (IOException ex) {
            log.error(ex.getMessage(), ex);
            return null;
        }
    }

    /**
     * Java Bean 不同对象之间字段值的复制
     * Bean复制的几种框架性能比较（Apache BeanUtils、 PropertyUtils、 Spring BeanUtils、 Cglib BeanCopier）
     */
    public static void copyProperties(Class<?> originClass, Class<?> targetClass, Object origin, Object target) {
        BeanCopier.create(originClass, targetClass, false)
                .copy(origin, target, null);
    }

    public static void parseJSON2Map(String jsonStr) throws IOException {
        JsonNode jsonNode = objectMapper.readTree(jsonStr);
        Iterator<Entry<String, JsonNode>> fieldIterator = jsonNode.fields();
        while (fieldIterator.hasNext()) {
            Entry<String, JsonNode> next = fieldIterator.next();
            System.out.println(next.getKey() + "------" + next.getValue().getNodeType().name() + "------" + next.getValue().asText());
        }
    }

}
